| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- <template>
- <!-- 分类 -->
- <div class="main-background">
- <!-- SEO -->
- <Head>
- <Title>厦门市文化遗产保护中心 - {{ channelName }}</Title>
- <Meta name="description" content="" />
- <Meta name="keywords" content="" />
- </Head>
- <!-- 轮播 -->
- <Carousel v-bind="carouselConfig" class="main-header-image carousel-light">
- <Slide
- v-for="(item, key) in carouselData.content.value"
- :key="key"
- class="main-header-image"
- >
- <img class="main-header-image" :src="item.image" />
- </Slide>
- <template #addons>
- <Navigation />
- <Pagination />
- </template>
- </Carousel>
- <!-- 主要内容 -->
- <div class="main-content">
- <div class="container">
- <div class="row">
- <!-- 左侧导航 -->
- <div class="col-12 col-sm-12 col-md-4 col-lg-3">
- <div class="sidebar">
- <div class="title">
- <h2>{{ channelName }}</h2>
- </div>
- <ul class="sidebar-menu">
- <li v-for="(item, key) in channelData.content.value?.childs" :key="key">
- <a v-if="item.type === 'link'" :href="item.outlink" target="_blank">{{ item.name }}</a>
- <router-link v-else :to="`/channel/${item.id}`" :class="{ 'active': item.id == channelId }">
- {{ item.name }}
- <Icon name="material-symbols-light:chevron-right" />
- </router-link>
- </li>
- <li v-if="channelData.content.value?.parent_id !== 0">
- <router-link :to="`/channel/${channelData.content.value?.parent_id}`">
- <div>
- <Icon name="material-symbols:undo" />
- 返回上一级
- </div>
- </router-link>
- </li>
- <li v-if="!channelData.content.value?.childs || channelData.content.value?.childs.length === 0" class="no-content">暂无相关子分类</li>
- </ul>
- </div>
- </div>
-
- <!-- 右侧内容 -->
- <div class="col-12 col-sm-12 col-md-8 col-lg-9">
- <div class="content">
- <div class="section-title">
- <h2 class="icon">{{ channelName }}</h2>
-
- <nav aria-label="breadcrumb">
- <ol class="breadcrumb">
- <li class="breadcrumb-item"><router-link to="/">首页</router-link></li>
- <li v-for="(item, key) in channelData.content.value?.parents" :key="key" class="breadcrumb-item">
- <a v-if="item.type === 'link'" :href="item.outlink" target="_blank">{{ item.name }}</a>
- <router-link v-else :to="`/channel/${item.id}`">{{ item.name }}</router-link>
- </li>
- <li class="breadcrumb-item active" aria-current="page">{{ channelName }}</li>
- </ol>
- </nav>
- </div>
-
- <!-- 文章列表 -->
- <SimplePageContentLoader :loader="articlesData">
- <div class="news-list">
- <div v-for="(item, key) in articlesData.content.value?.items" :key="key" class="news-item">
- <router-link :to="'/page/' + item.id" class="title">{{ item.title }}</router-link>
- <span class="date">{{ DateUtils.formatDate(new Date((item.createtime ||item.publishtime) * 1000), 'yyyy-MM-dd') }}</span>
- </div>
- <div v-if="!articlesData.content.value || articlesData.content.value.empty" class="no-news">暂无相关文章</div>
- </div>
- <!-- 分页 -->
- <SimplePagination
- v-if="articlesData.content.value"
- :currPage="articlesData.content.value.pageIndex"
- :allPage="articlesData.content.value.allPage"
- :maxCount="10"
- />
- </SimplePageContentLoader>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import { computed } from 'vue';
- import { Carousel, Slide, Pagination, Navigation } from 'vue3-carousel'
- import { useSSrSimpleDataLoader } from '@/composeable/SimpleDataLoader';
- import { DateUtils } from '@imengyu/imengyu-utils';
- import type { IChannel } from '~~/server/api/channel/[id]';
- import SimplePagination from '~/components/content/SimplePagination.vue';
- const carouselConfig : (typeof Carousel['props']) = {
- itemsToShow: 1,
- wrapAround: true,
- autoplay: 5000,
- }
- const route = useRoute();
- const channelId = parseInt(route.params.id as string);
- const channelData = await useSSrSimpleDataLoader('channel' + channelId, async () => {
- const res = await $fetch(`/api/channel/${channelId}`);
- if (!res.status)
- throw new Error(res.message);
- return res.data as IChannel & {
- childs: IChannel[];
- parents: IChannel[];
- };
- });
- const carouselData = await useSSrSimpleDataLoader('carousel' + channelId, async () => {
- const res = await $fetch(`/api/carousel`);
- if (!res.status)
- throw new Error(res.message);
- return res.data;
- });
- const articlesData = await useSSrSimpleDataLoader('articles' + channelId, async () => {
- const res = await $fetch('/api/article/byChannel', {
- method: 'GET',
- query: {
- channelId: channelId,
- page: route.query.page || 1,
- pageSize: 10,
- }
- });
- if (!res.status)
- throw new Error(res.message);
- if (res.data?.empty && channelData.content.value?.childs?.[0]) {
- // 没有文章时,并且有子分类时,尝试读取全部第一级子分类的文章
- const res = await $fetch('/api/article/byChannelAndOnLevelChild', {
- method: 'GET',
- query: {
- channelId: channelId,
- page: route.query.page || 1,
- pageSize: 10,
- }
- });
- if (!res.status)
- throw new Error(res.message);
- return res.data;
- }
- return res.data;
- });
- const channelName = computed(() => channelData.content.value?.name || '');
- watch(() => route.query.page, async (newVal, oldVal) => {
- if (newVal !== oldVal) {
- articlesData.loadData(undefined, true);
- }
- })
- </script>
- <style lang="scss">
- @use "sass:list";
- @use "sass:math";
- </style>
|